package com.brainhealth.customer.service.impl;

import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSONObject;
import com.brainhealth.common.constant.NumberConstants;
import com.brainhealth.common.enums.*;
import com.brainhealth.common.utils.DateUtils;
import com.brainhealth.customer.domain.Customer;
import com.brainhealth.customer.domain.RoomChatRecord;
import com.brainhealth.customer.domain.RoomChatTokens;
import com.brainhealth.customer.domain.RoomUserProperty;
import com.brainhealth.customer.domain.params.RoomChatParam;
import com.brainhealth.customer.domain.vo.ChatAiContentVO;
import com.brainhealth.customer.domain.vo.RemainChatVO;
import com.brainhealth.customer.domain.vo.RoomChatVO;
import com.brainhealth.customer.service.*;
import com.brainhealth.utils.CommonUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 个人空间聊天服务
 *
 * @author wll
 */
@Service
public class RoomChatServiceImpl implements IRoomChatService {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    IErnieBotService ernieBotService;

    @Autowired
    IAIChatService aiChatService;

    @Autowired
    IRoomChatTokensService roomChatTokensService;

    @Autowired
    IRoomChatRecordService roomChatRecordService;

    @Autowired
    IRoomUserPropertyService roomUserPropertyService;

    @Override
    public RemainChatVO getRemainChatPacket(HttpServletRequest request) {
        long ts = DateUtils.getTimeMillis();
        try {
            Long customerId = getCustomerId(ts, request);
            RoomChatTokens tokens = new RoomChatTokens();
            tokens.setCustomerId(customerId);
            List<RoomChatTokens> roomChatTokenList = roomChatTokensService.selectRoomChatTokensList(tokens);
            if (CollectionUtils.isEmpty(roomChatTokenList)) {
                RemainChatVO remainChatVO = new RemainChatVO();
                remainChatVO.setRemainPacketCount(Long.valueOf(NumberConstants.ZERO));
                return remainChatVO;
            }
            RoomChatTokens chatTokens = roomChatTokenList.get(0);
            if (null == chatTokens.getChatPacketSum() || null == chatTokens.getChatPacketUsed()) {
                logger.warn("ts:{}，用户{}总聊天包数或已使用聊天包数为空", ts, customerId);
                return null;
            }

            logger.info("ts:{}，用户{}总语言包{}已使用语言包{}", ts, customerId, chatTokens.getChatPacketSum(), chatTokens.getChatPacketUsed());
            Long longResult = chatTokens.getChatPacketSum() - chatTokens.getChatPacketUsed();
            logger.info("ts:{}，用户{}剩余语言包{}", ts, customerId, longResult);

            RoomUserProperty roomUserProperty = new RoomUserProperty();
            roomUserProperty.setCustomerId(customerId);
            roomUserProperty.setGoodsType(GoodsType.AIPackage.getCode());
            roomUserProperty.setGoodsStatus(PropertyStatusEnum.NOT_USED.getCode());
            roomUserProperty.setYn(YNEnum.NO.getCode());
            RoomUserProperty userProperty = roomUserPropertyService.getRoomUserProperty(roomUserProperty);
            Long propertyId = null==userProperty?null:userProperty.getPropertyId();

            RemainChatVO remainChatVO = new RemainChatVO();
            remainChatVO.setRemainPacketCount(longResult);
            remainChatVO.setChatPacketId(propertyId);
            return remainChatVO;
        } catch (Exception e) {
            logger.error("ts:{} ，查询用户剩余语言包，异常", ts, e);
            return null;
        }
    }

    private Long getCustomerId(Long ts, HttpServletRequest request) {
        Customer customer = CommonUtils.getCustomerByRequest(request);
        if (null == customer || null == customer.getCustomerId()) {
            logger.info("ts:{}，未找到用户信息", ts);
            return null;
        }
        Long customerId = customer.getCustomerId();
        return customerId;
    }

    @Override
    public ChatAiContentVO getChatContent(HttpServletRequest request, RoomChatParam roomChatParam) {
        long ts = DateUtils.getTimeMillis();
        try {
            Long customerId = getCustomerId(ts, request);
            checkRoomChatParam(roomChatParam, customerId);
            String accessToken = aiChatService.getAccessToken();
            JSONObject jsonObject = ernieBotService.getCompletion(accessToken, roomChatParam.getPrompt());

            String completion = ernieBotService.getErnieBotResult(jsonObject);
            Long totalTokens = ernieBotService.getTotalTokens(jsonObject, TokenTypeEnum.TOTAL_TOKENS);

            Long tokens = getRoomChatTokens(roomChatParam.getChatPacketId(), customerId);
            totalTokens = totalTokens + tokens;

            final Long finalTotalTokens = totalTokens;
            //保存聊天内容
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    saveRoomChatInfo(customerId, roomChatParam, jsonObject, finalTotalTokens);
                }
            };
            Thread thread = new Thread(task, "thread-save-room-chat-record");
            thread.start();

            //查询当前聊天包聊天总字数
            ChatAiContentVO chatAiContentVO = new ChatAiContentVO();
            chatAiContentVO.setChatContent(completion);
            chatAiContentVO.setTotalTokens(totalTokens);
            return chatAiContentVO;
        } catch (Exception e) {
            logger.info("ts:{} ，查询聊天内容，异常", ts, e);
            return null;
        }
    }

    void checkRoomChatParam(RoomChatParam roomChatParam, Long customerId) {
        Assert.notNull(roomChatParam.getChatPacketId(), "语音包ID不能为空");
        Assert.notNull(roomChatParam.getPrompt(), "问题不能为空");
        Assert.state(checkChatPacketId(roomChatParam.getChatPacketId(), customerId), "该语音包已使用完");
    }

    private Long getRoomChatTokens(Long chatPacketId, Long customerId) {
        RoomChatRecord record = new RoomChatRecord();
        record.setCustomerId(customerId);
        record.setChatPacketId(chatPacketId);
        Long tokens = roomChatRecordService.selectRoomChatTokens(record);
        tokens = null == tokens ? 0 : tokens;
        return tokens;
    }

    private boolean checkChatPacketId(Long chatPacketId, Long customerId) {
        Long roomChatTokens = getRoomChatTokens(chatPacketId, customerId);
        return roomChatTokens < NumberConstants.TWO_THOUSAND;
    }

    @Transactional
    public Integer saveRoomChatInfo(Long customerId, RoomChatParam roomChatParam, JSONObject jsonObject, Long totalTokens) {
        long ts = DateUtils.getTimeMillis();
        try {
            logger.info("ts:{} ，保存文心一言聊天记录，入参{}，结果{}", ts, roomChatParam, jsonObject);
            //1.保存聊天记录
            RoomChatRecord promptRoomChatRecord = constructRoomChatRecord(customerId, roomChatParam, jsonObject, AIRoleEnum.PROMPT);
            RoomChatRecord completionRoomChatRecord = constructRoomChatRecord(customerId, roomChatParam, jsonObject, AIRoleEnum.COMPLETION);
            List<RoomChatRecord> chatAiRecordList = new ArrayList<>();
            chatAiRecordList.add(promptRoomChatRecord);
            chatAiRecordList.add(completionRoomChatRecord);
            int insertRecordResult = roomChatRecordService.batchInsertRoomChatRecord(chatAiRecordList);
            logger.info("ts:{} ，新增文心一言聊天记录，结果:{}", ts, insertRecordResult);

            //2.更新聊天字数
            Date now = DateUtils.getNowDate();
            String strCustomerId = null == customerId ? "" : String.valueOf(customerId);
            RoomChatTokens roomChatTokens = new RoomChatTokens();
            roomChatTokens.setCustomerId(customerId);
            List<RoomChatTokens> roomChatTokensList = roomChatTokensService.selectRoomChatTokensList(roomChatTokens);
            if (CollectionUtils.isNotEmpty(roomChatTokensList)) {
                roomChatTokens = roomChatTokensList.get(0);

                Long chatTotalTokens = roomChatTokens.getCompletedChatTokens();
                chatTotalTokens = chatTotalTokens + ernieBotService.getTotalTokens(jsonObject, TokenTypeEnum.TOTAL_TOKENS);
                roomChatTokens.setCompletedChatTokens(chatTotalTokens);
                if (totalTokens > NumberConstants.TWO_THOUSAND) {
                    roomChatTokens.setChatPacketUsed(roomChatTokens.getChatPacketUsed() + 1);
                }
                roomChatTokens.setUpdateUser(strCustomerId);
                roomChatTokens.setUpdateTime(now);
                int updateResult = roomChatTokensService.updateRoomChatTokens(roomChatTokens);
                logger.info("ts:{} ，更新文心一言聊天字数(tokens)，结果:{}", ts, updateResult);
            } else {
                roomChatTokens = new RoomChatTokens();
                roomChatTokens.setCustomerId(customerId);
                roomChatTokens.setChatPacketSum(Long.valueOf(NumberConstants.ONE));
                roomChatTokens.setChatPacketUsed(Long.valueOf(NumberConstants.ZERO));
                roomChatTokens.setCompletedChatTokens(ernieBotService.getTotalTokens(jsonObject, TokenTypeEnum.TOTAL_TOKENS));
                roomChatTokens.setYn(YNEnum.NO.getCode());
                roomChatTokens.setCreateUser(strCustomerId);
                roomChatTokens.setCreateTime(now);
                int insertResult = roomChatTokensService.insertRoomChatTokens(roomChatTokens);
                logger.info("ts:{} ，新增文心一言聊天字数，结果:{}", ts, insertResult);
            }

            if (totalTokens > NumberConstants.TWO_THOUSAND) {
                RoomUserProperty roomUserProperty = new RoomUserProperty();
                roomUserProperty.setCustomerId(customerId);
                roomUserProperty.setPropertyId(roomChatParam.getChatPacketId());
                roomUserProperty.setGoodsStatus(PropertyStatusEnum.USED.getCode());
                roomUserProperty.setUpdateUser(strCustomerId);
                roomUserProperty.setUpdateTime(now);
                int updateResult = roomUserPropertyService.updateRoomUserPropertyByPropertyId(roomUserProperty);
                logger.info("ts:{} ，更新用户道具状态，结果:{}", ts, updateResult);
            }
            //TODO: 判断如果总字数大于2000
            // 则更新主表已使用聊天包个数
            // 且更新道具表道具状态

            return insertRecordResult;
        } catch (Exception e) {
            logger.info("ts:{} ，新增文心一言聊天记录，异常", ts, e);
            return null;
        }
    }

    private RoomChatRecord constructRoomChatRecord(Long customerId, RoomChatParam chatParam, JSONObject object, AIRoleEnum role) {
        if (null == object) {
            return null;
        }

        String chatContent;
        Long tokens;
        if (AIRoleEnum.PROMPT.equals(role)) {
            chatContent = chatParam.getPrompt();
            //问题tokens数
            tokens = ernieBotService.getTotalTokens(object, TokenTypeEnum.PROMPT_TOKENS);
        } else {
            chatContent = ernieBotService.getErnieBotResult(object);
            //答案tokens数
            tokens = ernieBotService.getTotalTokens(object, TokenTypeEnum.COMPLETION_TOKENS);
        }

        RoomChatRecord roomChatRecord = new RoomChatRecord();
        roomChatRecord.setCustomerId(customerId);
        roomChatRecord.setChatPacketId(chatParam.getChatPacketId());
        roomChatRecord.setRole(role.getCode());
        roomChatRecord.setChatContent(chatContent);
        roomChatRecord.setTokens(tokens);

        roomChatRecord.setYn(YNEnum.NO.getCode());
        String strCustomerId = null == customerId ? "" : String.valueOf(customerId);
        roomChatRecord.setCreateUser(strCustomerId);
        Date now = DateUtils.getNowDate();
        roomChatRecord.setCreateTime(now);
        roomChatRecord.setUpdateUser(strCustomerId);
        roomChatRecord.setUpdateTime(now);

        return roomChatRecord;
    }

    @Override
    public List<RoomChatVO> getChatList(HttpServletRequest request) {
        long ts = DateUtils.getTimeMillis();
        try {
            Long customerId = getCustomerId(ts, request);
            //Long customerId = 6l;
            List<Long> packetList = roomChatRecordService.selectChatPacketIdList(customerId);
            RoomChatRecord roomChatRecord = new RoomChatRecord();
            roomChatRecord.setCustomerId(customerId);
            roomChatRecord.setYn(YNEnum.NO.getCode());
            roomChatRecord.setChatPacketIdList(packetList);
            List<RoomChatRecord> roomChatRecordList = roomChatRecordService.selectRoomChatRecordList(roomChatRecord);
            if (CollectionUtils.isEmpty(roomChatRecordList)) {
                logger.info("ts:{} ，用户{}聊天记录为空", ts, customerId);
                return new ArrayList<>();
            }
            logger.info("ts:{} ，用户{}聊天记录数{}", ts, customerId, roomChatRecordList.size());
            List<RoomChatVO> roomChatVOList = new ArrayList<>();
            for (RoomChatRecord chatRecord : roomChatRecordList) {
                RoomChatVO roomChatVO = new RoomChatVO();
                BeanUtils.copyProperties(chatRecord, roomChatVO);
                roomChatVOList.add(roomChatVO);
            }

            return roomChatVOList;
        } catch (Exception e) {
            logger.error("ts:{} ，个人空间，查询历史聊天记录异常", ts, e);
            return null;
        }
    }
}
